package com.shunda.ysdgj.manager.service.impl.system;

import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.crypto.digest.DigestUtil;
import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.conditions.query.LambdaQueryChainWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.IService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.shunda.ysdgj.common.exception.CustomException;
import com.shunda.ysdgj.common.util.ValidateUtil;
import com.shunda.ysdgj.manager.mapper.system.SysUserMapper;
import com.shunda.ysdgj.manager.service.system.SysMenuService;
import com.shunda.ysdgj.manager.service.system.SysRoleMenuService;
import com.shunda.ysdgj.manager.service.system.SysUserRoleService;
import com.shunda.ysdgj.manager.service.system.SysUserService;
import com.shunda.ysdgj.model.dto.base.IdsDto;
import com.shunda.ysdgj.model.dto.system.LoginDto;
import com.shunda.ysdgj.model.dto.system.SysUserFindDto;
import com.shunda.ysdgj.model.entity.system.SysMenu;
import com.shunda.ysdgj.model.entity.system.SysUser;
import com.shunda.ysdgj.model.enums.TimeEnum;
import com.shunda.ysdgj.model.vo.ResultCodeEnum;
import com.shunda.ysdgj.model.vo.system.LoginVo;
import lombok.RequiredArgsConstructor;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;
import java.util.concurrent.TimeUnit;

@Service
@RequiredArgsConstructor
public class SysUserServiceImpl extends ServiceImpl<SysUserMapper, SysUser> implements SysUserService, IService<SysUser> {

    private final RedisTemplate<String, String> redisTemplate;
    private final SysUserRoleService sysUserRoleService;
    private final SysRoleMenuService sysRoleMenuService;
    private final SysMenuService sysMenuService;

    @Override
    public IPage<SysUser> findByPage(SysUserFindDto sysUserFindDto) {
        if (ValidateUtil.isNotLong(sysUserFindDto.getCurrent())) {
            sysUserFindDto.setCurrent(1L);
        }
        if (ValidateUtil.isNotLong(sysUserFindDto.getSize())) {
            sysUserFindDto.setSize(10L);
        }
        LambdaQueryChainWrapper<SysUser> lambdaQuery = lambdaQuery();
        if (StrUtil.isNotEmpty(sysUserFindDto.getUserAccount())) {
            lambdaQuery.like(SysUser::getUserAccount, sysUserFindDto.getUserAccount());
        }
        if (StrUtil.isNotEmpty(sysUserFindDto.getUserName())) {
            lambdaQuery.like(SysUser::getUserName, sysUserFindDto.getUserName());
        }
        if (StrUtil.isNotEmpty(sysUserFindDto.getUserMobile())) {
            lambdaQuery.like(SysUser::getUserMobile, sysUserFindDto.getUserMobile());
        }
        if (StrUtil.isNotEmpty(sysUserFindDto.getCreateBeginTime()) && StrUtil.isNotEmpty(sysUserFindDto.getCreateEndTime())) {
            lambdaQuery.between(SysUser::getCreated, sysUserFindDto.getCreateBeginTime(), sysUserFindDto.getCreateEndTime());
        }
        IPage<SysUser> page = new Page<>(sysUserFindDto.getCurrent(), sysUserFindDto.getSize());
        return lambdaQuery.page(page);
    }

    @Override
    public boolean add(SysUser sysUser) {
        if (ValidateUtil.isBlank(sysUser.getUserAccount())
                || ValidateUtil.isBlank(sysUser.getUserPassword())
                || ValidateUtil.isBlank(sysUser.getUserName())
                || ValidateUtil.isBlank(sysUser.getUserMobile())) {
            throw new CustomException(ResultCodeEnum.PARAM_ERROR);
        }
        if (ValidateUtil.isNotLimitLen(6, 12, sysUser.getUserPassword())) {
            throw new CustomException(ResultCodeEnum.ADMIN_PASSWORD_Len_ERROR);
        }
        if (ValidateUtil.isNotMobile(sysUser.getUserMobile())) {
            throw new CustomException(ResultCodeEnum.MOBILE_ERROR);
        }
        LambdaQueryChainWrapper<SysUser> lambdaQuery = lambdaQuery();
        Long count = lambdaQuery.eq(SysUser::getUserAccount, sysUser.getUserAccount()).count();
        if (count > 0) {
            throw new CustomException(ResultCodeEnum.ADMIN_LOGIN_ACCOUNT_EXISTED);
        }
        sysUser.setUserPassword(DigestUtil.md5Hex(sysUser.getUserPassword()));
        sysUser.setId(null);
        return save(sysUser);
    }

    public boolean modify(SysUser sysUser) {
        if (ValidateUtil.isNotLong(sysUser.getId())
                || ValidateUtil.isBlank(sysUser.getUserName())
                || ValidateUtil.isBlank(sysUser.getUserMobile())) {
            throw new CustomException(ResultCodeEnum.PARAM_ERROR);
        }
        if (ValidateUtil.isBlank(sysUser.getUserPassword())) {
            sysUser.setUserPassword(null);
        } else {
            if (ValidateUtil.isNotLimitLen(6, 12, sysUser.getUserPassword())) {
                throw new CustomException(ResultCodeEnum.ADMIN_PASSWORD_Len_ERROR);
            } else {
                sysUser.setUserPassword(DigestUtil.md5Hex(sysUser.getUserPassword()));
            }
        }
        if (ValidateUtil.isNotMobile(sysUser.getUserMobile())) {
            throw new CustomException(ResultCodeEnum.MOBILE_ERROR);
        }
        return updateById(sysUser);
    }

    // 管理员登录
    @Override
    public LoginVo login(LoginDto loginDto) {
        if (ValidateUtil.isBlank(loginDto.getUserAccount())
                || ValidateUtil.isBlank(loginDto.getUserPassword())
                || ValidateUtil.isBlank(loginDto.getCodeKey())
                || ValidateUtil.isBlank(loginDto.getCodeValue())
                || ValidateUtil.isNotLimitLen(6, 12, loginDto.getUserPassword())) {
            throw new CustomException(ResultCodeEnum.PARAM_ERROR);
        }

        String codeKey = loginDto.getCodeKey();
        String codeValue = redisTemplate.opsForValue().get(codeKey);
        if (codeValue == null || !codeValue.equalsIgnoreCase(loginDto.getCodeValue())) {
            throw new CustomException(ResultCodeEnum.CAPTCHA_ERROR);
        }
        redisTemplate.delete(codeKey);

        SysUser sysUser = lambdaQuery().eq(SysUser::getUserAccount, loginDto.getUserAccount()).one();
        if (sysUser == null) {
            throw new CustomException(ResultCodeEnum.ADMIN_ACCOUNT_NOT_EXISTED);
        }
        if (!sysUser.getUserPassword().equals(DigestUtil.md5Hex(loginDto.getUserPassword()))) {
            throw new CustomException(ResultCodeEnum.ADMIN_PASSWORD_ERROR);
        }
        if (sysUser.getUserStatus() != 1) {
            throw new CustomException(ResultCodeEnum.ACCOUNT_DISABLED);
        }

        String token = IdUtil.simpleUUID();
        redisTemplate.opsForValue().set(token, JSON.toJSONString(sysUser), TimeEnum.ADMIN_LOGIN_DAYS.getTime(), TimeUnit.DAYS);
        LoginVo loginVo = new LoginVo();
        loginVo.setToken(token);

        return loginVo;
    }

    @Transactional
    public boolean deleteByIds(IdsDto idsDto) {
        List<Long> ids = idsDto.getIds();
        if (ids.isEmpty()) {
            throw new CustomException(ResultCodeEnum.PARAM_ERROR);
        }
        return removeByIds(ids);
    }

    // 获取当前登录管理员信息
    @Override
    public SysUser getUserInfo(String token) {
        String sysUserJsonStr = redisTemplate.opsForValue().get(token);
        if (sysUserJsonStr == null || sysUserJsonStr.isEmpty()) {
            throw new CustomException(ResultCodeEnum.LOGIN_EXPIRED);
        }
        return JSON.parseObject(sysUserJsonStr, SysUser.class);
    }

    // 获取当前登录用户可操作的菜单
    public List<SysMenu> getUserMenus(String token) {
        boolean isSuperUser = false;
        List<SysMenu> menuList;
        String sysUserJsonStr = redisTemplate.opsForValue().get(token);
        SysUser user = JSON.parseObject(sysUserJsonStr, SysUser.class);
        if (user == null) {
            throw new CustomException(ResultCodeEnum.LOGIN_EXPIRED);
        }
        List<Long> roleIds = sysUserRoleService.getAssignedRoleIds(user.getId());
        for (long roleId : roleIds) {
            if (roleId == 1) {
                isSuperUser = true;
                break;
            }
        }
        if (isSuperUser) {
            // 超级管理员直接返回所有可操作菜单
            menuList = sysMenuService.findAllAvailable();
        } else {
            List<Long> menuIds = sysRoleMenuService.getAssignedMenuIdsByRoleIds(roleIds);
            menuList = sysMenuService.findByIds(menuIds);
        }
        return menuList;
    }

    @Override
    public void logout(String token) {
        if (ValidateUtil.isNotBlank(token)) {
            redisTemplate.delete(token);
        }
    }

}
